package com.yjha.lzmarathonsys.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yjha.lzmarathonsys.bean.TbLike;
import com.yjha.lzmarathonsys.bean.TbPersonClockin;
import com.yjha.lzmarathonsys.bean.TbSpecialClockin;
import com.yjha.lzmarathonsys.config.RabbitmqConfig;
import com.yjha.lzmarathonsys.mapper.TbLikeMapper;
import com.yjha.lzmarathonsys.service.TbLikeService;
import com.yjha.lzmarathonsys.service.TbPersonClockinService;
import com.yjha.lzmarathonsys.service.TbSpecialClockinService;
import com.yjha.lzmarathonsys.utils.JwtUtils;
import com.yjha.lzmarathonsys.utils.PageUtils;
import com.yjha.lzmarathonsys.utils.Query;
import com.yjha.lzmarathonsys.utils.R;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service("tbLikeService")
public class TbLikeServiceImpl extends ServiceImpl<TbLikeMapper, TbLike> implements TbLikeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private DefaultRedisScript<Long> likeScript; // 注入Lua脚本Bean

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private TbPersonClockinService tbPersonClockinService;

    @Autowired
    private TbSpecialClockinService tbSpecialClockinService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<TbLike> page = this.page(
                new Query<TbLike>().getPage(params),
                new QueryWrapper<TbLike>()
        );

        return new PageUtils(page);
    }

    @Override
    public R like(TbLike tbLike, HttpServletRequest request) {
        // 1. 验证目标状态
        String targetId = tbLike.getTargetId();
        if (!isTargetValid(targetId)) {
            return R.error(400, "该打卡审核未通过，无法点赞");
        }

        // 2. 获取用户身份
        String token = JwtUtils.getTokenFromRequest(request);

        String userId = JwtUtils.getOpenId(token);

        if (userId == null) {
            return R.error(401, "未授权");
        }

        // 3. 执行原子化点赞操作
        String redisKey = "like:target:" + targetId;
        try {
            // 3.1 执行Lua脚本（包含缓存初始化逻辑）
            Long result = executeLikeScript(redisKey, userId);

            // 3.2 处理数据库同步
            syncDatabase(targetId, userId, result);

            // 4. 获取最新计数
            Long count = getLikeCountByTarGet(targetId);

            return R.ok().put("action", result).put("count", count);
        } catch (Exception e) {

            return R.error("操作失败");
        }
    }

    // 验证目标状态方法
    private boolean isTargetValid(String targetId) {
        TbPersonClockin person = tbPersonClockinService.getOne(
                new QueryWrapper<TbPersonClockin>().eq("tb_uuid", targetId));
        if (person != null) return "0".equals(person.getTbStatus());

        TbSpecialClockin special = tbSpecialClockinService.getOne(
                new QueryWrapper<TbSpecialClockin>().eq("tb_uuid", targetId));
        return special != null && "0".equals(special.getTbStatus());
    }

    // 执行Lua脚本（含缓存初始化）
    private Long executeLikeScript(String redisKey, String userId) {
        String targetId = extractTargetIdFromRedisKey(redisKey); // 从redisKey解析targetId

        // 检查缓存是否存在，不存在则加载数据
        if (!redisTemplate.hasKey(redisKey)) {
            String lockKey = "lock:" + redisKey;
            boolean locked = false;
            try {
                // 尝试获取分布式锁，设置5秒过期防止死锁
                locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", Duration.ofSeconds(5));
                if (locked) {
                    // 双重检查，防止其他线程已加载
                    if (!redisTemplate.hasKey(redisKey)) {
                        // 查询数据库获取所有点赞该target的用户ID
                        List<TbLike> likes = baseMapper.selectList(
                                new QueryWrapper<TbLike>().eq("target_id", targetId)
                        );
                        if (!likes.isEmpty()) {
                            String[] userIds = likes.stream()
                                    .map(TbLike::getUserId)
                                    .toArray(String[]::new);
                            redisTemplate.opsForSet().add(redisKey, userIds);
                        }
                        // 设置缓存过期时间
                        redisTemplate.expire(redisKey, 7, TimeUnit.DAYS);
                    }
                } else {
                    // 获取锁失败，可重试或抛出异常（根据业务需求调整）
                    throw new RuntimeException("系统繁忙，请稍后重试");
                }
            } finally {
                if (locked) {
                    redisTemplate.delete(lockKey);
                }
            }
        }

        // 执行Lua脚本
        return (Long) redisTemplate.execute(
                likeScript,
                Arrays.asList(redisKey, "lock:" + redisKey),
                userId,
                System.currentTimeMillis()
        );
    }

    private String extractTargetIdFromRedisKey(String redisKey) {
        String prefix = "like:target:";
        return redisKey.substring(prefix.length());
    }


    // 数据库同步方法
    private void syncDatabase(String targetId, String userId, Long action) {
        QueryWrapper<TbLike> query = new QueryWrapper<TbLike>()
                .eq("target_id", targetId)
                .eq("user_id", userId);

        if (action == 1) { // 点赞
            if (!baseMapper.exists(query)) {
                TbLike like = new TbLike();
                like.setUserId(userId);
                like.setTargetId(targetId);
                like.setCreatedAt(new Date());
                baseMapper.insert(like);
            }
        } else { // 取消点赞
            baseMapper.delete(query);
        }
    }

    // 获取点赞数（含缓存重建）
    private Long getLikeCountByTarGet(String targetId) {
        return this.count(new QueryWrapper<TbLike>().eq("target_id", targetId));
    }

    @Override
    public R getLikeCount(String targetId) {
        // 2. 查Redis
        String redisKey = "like:target:" + targetId;
        Long count  = redisTemplate.opsForSet().size(redisKey);
        if (count != null) {
            return R.ok().put("count", count);
        }

        // 3. 兜底查数据库
        count = this.baseMapper.selectCount(new QueryWrapper<TbLike>()
                .eq("target_id", targetId));

        redisTemplate.opsForSet().add(redisKey, Collections.emptyList()); // 重建缓存

        return R.ok().put("count", count);
    }
}
